package nf;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

class ImageViewer extends JPanel implements MouseMotionListener, MouseListener, MouseWheelListener, ComponentListener {
	
	private static final long serialVersionUID = -4995262367517324506L;
	private BufferedImage img = null;
	private int realWidth = 0;
	private int realHeight = 0;
	private int width = 0;
	private int height = 0;
	private int offsetX = 0;
	private int offsetY = 0;
	private int dragStartX = 0;
	private int dragStartY = 0;
	private int offsetStartX = 0;
	private int offsetStartY = 0;
	private int zoomLevel = 0;
	
	private int lastMX = 0;
	private int lastMY = 0;
	
	private boolean dragging = false;
	
	private int multi = 1;
	private int div = 1;
	
	public ImageViewer(BufferedImage img)
	{
		super(true);
		
		this.img = img;
		
		width = realWidth = img.getWidth();
		height = realHeight = img.getHeight();
		
		this.addMouseMotionListener(this);
		this.addMouseListener(this);
		this.addComponentListener(this);
		this.addMouseWheelListener(this);
	}
	
	@Override
	public void paint(Graphics gg)
	{
		Graphics2D g = (Graphics2D)gg;
		g.setBackground(Color.black);
		g.clearRect(0, 0, getWidth(), getHeight());
		
		if(multi == 1 && div == 1)
			g.drawImage(img, offsetX, offsetY, null);
		else
			g.drawImage(img, offsetX, offsetY, width, height, null);
		
		if(multi != 1 || div != 1)
		{
			g.setColor(new Color(0, 0, 0, 128));
			g.fillRect(25, 25, 75, 25);
			g.setColor(Color.white);
			g.drawString((100 * multi) / div + "%", 50, 42);
		}
	}

	@Override
	public void mouseDragged(MouseEvent arg0) {
		
		if(dragging)
		{
			offsetX = offsetStartX + (arg0.getX() - dragStartX);
			offsetY = offsetStartY + (arg0.getY() - dragStartY);
			
			checkBounds();
			
			repaint();
		}
		
		lastMX = arg0.getX();
		lastMY = arg0.getY();
	}
	
	private void checkBounds()
	{
		if(getWidth() > width + 20)
		{
			offsetX = getWidth() / 2 - width / 2;
		}
		else
		{
			if(offsetX > 10) offsetX = 10;
			if(offsetX < (getWidth() - width - 10)) offsetX = (getWidth() - width - 10);
		}
		
		if(getHeight() > height + 20)
		{
			offsetY = getHeight() / 2 - height / 2;
		}
		else
		{
			if(offsetY > 10) offsetY = 10;
			if(offsetY < (getHeight() - height - 10)) offsetY = (getHeight() - height - 10);
		}
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
		if(dragging)
		{
			offsetX = offsetStartX + (arg0.getX() - dragStartX);
			offsetY = offsetStartY + (arg0.getY() - dragStartY);
			
			checkBounds();
			
			repaint();
		}
		
		lastMX = arg0.getX();
		lastMY = arg0.getY();
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		//System.out.println("Mouse pressed! " + arg0.getButton());
		if(arg0.getButton() == MouseEvent.BUTTON1)
		{
			dragging = true;
			dragStartX = arg0.getX();
			dragStartY = arg0.getY();
			offsetStartX = offsetX;
			offsetStartY = offsetY;
		}
		
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		if(arg0.getButton() == MouseEvent.BUTTON1)
		{
			dragging = false;
		}	
		
	}

	@Override
	public void componentHidden(ComponentEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void componentMoved(ComponentEvent e) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void componentResized(ComponentEvent e) {
		
		checkBounds();
	}

	@Override
	public void componentShown(ComponentEvent e) {
		// TODO Auto-generated method stub
		
	}

	private void updateZoomLevel(int lvl)
	{
		if(lvl < -3) lvl = -3;
		if(lvl > 3) lvl = 3;
		
		if(lvl == zoomLevel) return;
		zoomLevel = lvl;
		
		int imageSpaceX = (((lastMX - offsetX) * div) / multi);
		int imageSpaceY = (((lastMY - offsetY) * div) / multi);
		
		switch(lvl)
		{
		case -3:
			multi = 1;
			div = 8;
			break;
			
		case -2:
			multi = 1;
			div = 4;
			break;
			
		case -1:
			multi = 1;
			div = 2;
			break;
			
		case 0:
			multi = 1;
			div = 1;
			break;
			
		case 1:
			multi = 2;
			div = 1;
			break;
			
		case 2:
			multi = 4;
			div = 1;
			break;
			
		case 3:
			multi = 8;
			div = 1;
			break;
		}
		
		width = (realWidth * multi) / div;
		height = (realHeight * multi) / div;
		
		offsetX = lastMX - ((imageSpaceX * multi) / div);
		offsetY = lastMY - ((imageSpaceY * multi) / div);
		
		checkBounds();
		repaint();
	}
	
	@Override
	public void mouseWheelMoved(MouseWheelEvent arg0) {
		if(arg0.getWheelRotation() > 0)
		{
			//System.out.println("Positive");
			updateZoomLevel(zoomLevel - 1);
		}
		else
		{
			//System.out.println("Negative");
			updateZoomLevel(zoomLevel + 1);
		}
		
	}

}
